import { schema } from './modules/validate';
import Joi from 'joi';
const log4js = require('koa-log4');
const cors = require('@koa/cors');
import config from './config';
import Koa from 'koa';
import helmet from 'koa-helmet';
import bodyParser from 'koa-bodyparser';
import { sendMail, sendError } from './modules/mail';

export type PostDTO = {
  name: string;
  email: string;
  type: number;
  city: string;
  telphone?: string;
  job?: string;
  company?: string;
  address?: string;
  area?: number;
  message?: string;
};

log4js.configure(config.log);
const app = new Koa();
const ipPools = new Map<string, number>();

const MAX_REQUEST = 10;
const interceptorInterval = 1000 * 60 * 60 * 24;

setInterval(() => {
  ipPools.clear();
}, interceptorInterval)

app.use(cors());
const httpLog = log4js.getLogger('http');
const logger = log4js.getLogger();
const errorLog = log4js.getLogger('error');

app.use(bodyParser());
app.use(helmet());

app.use(log4js.koaLogger(httpLog, { level: 'auto' }));

// logger
app.use(async (ctx, next) => {
  try {
    const start = Date.now();
    await next();
    const ms = Date.now() - start;
    logger.info(
      `${new Date().toDateString()} ${ctx.method} ${ctx.url} - ${ms}ms - ${
        ctx.querystring
      } - ${ctx.request.body && JSON.stringify(ctx.request.body)}`
    );
  } catch (e) {
    errorLog.error(
      `${e.code || '-'}:${e.message}:\n ${ctx.method} ${ctx.url}:${ctx.request
        .body && JSON.stringify(ctx.request.body)}`
    );
    ctx.throw(e.code || 400, e.message);
  }
});

app.use(ctx => {
  if ((ctx.url === '/' || ctx.url === '/api') && ctx.method === 'POST') {
    const intercepted = ipInterceptor(ctx.ip);
    if (intercepted) {
      ctx.throw(400, new Error('发送失败，请稍后重试'));
    }
    const { error, value } = Joi.validate(ctx.request.body || {}, schema);

    if (error) {
      ctx.throw(400, error);
    }
    sendMail(value as PostDTO);

    return (ctx.body = '发送成功');
  }
  ctx.throw(404);
});

const ipInterceptor = (ip: string) => {
  const currentTime = (ipPools.get(ip) || 0) + 1;
  if (currentTime > MAX_REQUEST) {
    return true;
  } else {
    ipPools.set(ip, currentTime);
    return false;
  }
}

process.on('uncaughtException', function(error) {
  sendError(`未捕获错误: ${error.message} - ${new Date().toLocaleString()}`);
});

app.listen(3000, () => {
  console.log('listen 3000, node_env = ', process.env.NODE_ENV);
});
